/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.game.core.net.handler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.kodgames.core.threadPool.OrderedThreadPoolExecutor;
import com.game.core.net.common.RemoteNode;
import com.game.core.net.message.InternalMessage;
import com.game.core.net.task.MessageTask;
import com.game.core.service.AbstractMessageService;

/**
 *
 * @author mrui
 */
public abstract class BaseMessageHandler<T>
{
	 private static final Logger logger =
	 LoggerFactory.getLogger(BaseMessageHandler.class);

	// public enum HandlerAction { CONTINUE, TERMINAL}
	OrderedThreadPoolExecutor executor;
	Class<? extends AbstractMessageService> serviceClass;

	void setExecutor(OrderedThreadPoolExecutor executor)
	{
		this.executor = executor;
	}
	
	void setServiceClass(Class<? extends AbstractMessageService> serviceClass)
	{
		this.serviceClass = serviceClass;
	}

	/**
	 * Invoked when a message object (e.g: {@link ChannelBuffer}) was received
	 * from a remote peer.
	 */
	@SuppressWarnings("unchecked")
	public boolean handleMessage(OrderedThreadPoolExecutor parentExecutor, final AbstractMessageInitializer msgInitializer, final InternalMessage message)
	{
		if (executor == null || parentExecutor == executor)
		{
			if (message.getProtocolID() != 0)
			{
				//Class<?> msgClass = msgInitializer.getMessageClass(message.getProtocolID());

				if (msgInitializer.getMsgHandlerType() == AbstractMessageInitializer.CUSTOMIZEMESSAGE_HANDLER)
				{
					handleMessage(message.getRemoteNode(), message.getProtocolID(), (T) message.getMessage());
				}
				else if (msgInitializer.getMsgHandlerType() == AbstractMessageInitializer.PROTOBUF_HANDLER)
				{
					handleMessage(message.getRemoteNode(), message.getProtocolID(), message.getCallback(), (T) message.getMessage());
				}
				else if (msgInitializer.getMsgHandlerType() == AbstractMessageInitializer.BYTEARRAY_HANDLER)
				{
					handleMessage(message.getRemoteNode(), message.getProtocolID(), message.getCallback(), (T) message.getMessage());
				}
			}
			else if (message.getRemoteNode().getChannel().isActive())
			{
				handleConnectionActive(message.getRemoteNode());
			}
			else if (message.getRemoteNode().getChannel().isActive() == false)
			{
				handleConnectionInactive(message.getRemoteNode());
			}
			else
			{
				// TODO:
			}
			return true;
		}

		if (executor != null)
		{
			executor.execute(new MessageTask(msgInitializer, message, this)
			{
				@Override
				public void run()
				{
					logger.debug("handleMessage.run: run begin. key is " + this.getKey());
					try
					{
						handleMessage(executor, msgInitializer, message);
					}
					catch (Exception e)
					{
						logger.error("Exception err={}",e.toString());
					}
					logger.debug("handleMessage.run: run end. key is " + this.getKey());
				}
			});
			return false;
		}
		return true;
	}

	@SuppressWarnings("unchecked")
	public Object getMessageKey(AbstractMessageInitializer msgInitializer, InternalMessage message)
	{
		if (message.getProtocolID() == 0)
		{
			return getMessageKey(message.getRemoteNode());
		}
		else if (msgInitializer.getMsgHandlerType() == AbstractMessageInitializer.CUSTOMIZEMESSAGE_HANDLER)
		{
			return getMessageKey(message.getRemoteNode(), message.getProtocolID(), (T) message.getMessage());
		}
		else if (msgInitializer.getMsgHandlerType() == AbstractMessageInitializer.PROTOBUF_HANDLER)
		{
			return getMessageKey(message.getRemoteNode(), message.getProtocolID(), (T) message.getMessage());
		}
		else if (msgInitializer.getMsgHandlerType() == AbstractMessageInitializer.BYTEARRAY_HANDLER)
		{
			return getMessageKey(message.getRemoteNode(), message.getProtocolID(), (T) message.getMessage());
		}
		return null;
	}

	public abstract void handleMessage(RemoteNode remoteNode, int protocolID, T message);

	public abstract void handleMessage(RemoteNode remoteNode, int protocolID, int callback, T buffer);

	public abstract void handleConnectionActive(RemoteNode remoteNode);

	public abstract void handleConnectionInactive(RemoteNode remoteNode);

	/**
	 * 如果在messageInitializer里设置了BeforeMessageExecutor或将此Handler和MessageExecutor绑定了
	 * ，在线程池会保证相同MessageKey的消息先后执行顺@param remoteNode
	 * 
	 * @param t
	 * @param buffer
	 * @return
	 */
	public abstract Object getMessageKey(RemoteNode remoteNode, int protocoliD, T t);

	/**
	 * 如果在messageInitializer里设置了BeforeMessageExecutor或将此Handler和MessageExecutor绑定了
	 * ，在线程池会保证相同MessageKey的消息先后执行顺@param remoteNode
	 * 
	 * @param t
	 * @param buffer
	 * @return
	 */
	public abstract Object getMessageKey(RemoteNode remoteNode);
}
